#include "ThreadCache.h"
#include "../CentralCache/CentralCache.h"
// static thread_local size_t cnt1 = 0;
// static thread_local size_t cnt2 = 0;
void* ThreadCache::FetchFromCentralCache(size_t alignSize, size_t index)
{
	//从CentralCache中取,怎么取?
	//慢开始反馈调节算法
	//SizeMove实际框定上限:通过min限制,使得申请数量慢慢增长至上限(满增长),而后保持不变
	//alignSize大的,上限小;alignSize小的,上限高
	size_t batchNum = std::min(SizeClass::NumMoveSize(alignSize),_freeLists[index].MaxNum());
	if(batchNum == _freeLists[index].MaxNum() && batchNum != SizeClass::NumMoveSize(alignSize))
	{
		_freeLists[index].MaxNum() += 5;//这里可以控制慢启动速度,针对小内存块,大内存块没有什么作用
	}
	
	//存储到获取到的自由链表
	void* start = nullptr;
	void* end = nullptr;
	size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start,end,alignSize,batchNum,index);

	assert(actualNum > 0);//至少给一个
	if(actualNum == 1)
	{
		assert(start == end);
		return start;//返回申请的要使用的一块内存空间,即不加入freeList中
	}
	else
	{
		_freeLists[index].PushRange(FreeList::GetPtr(start),end,actualNum - 1);//注意这是GetPtr(start),因此实际插入到freelist中的应减去1
		return start;
	}
	return nullptr;
}

void* ThreadCache::Allocate(size_t size)
{
	assert(size <= MAX_BYTES);
	size_t alignSize = SizeClass::RoundUp(size);
	size_t index = SizeClass::Index(alignSize);
	void* ptr = nullptr;
	if (!_freeLists[index].Empty())
	{
		ptr =  _freeLists[index].Pop();
	}
	else
	{
		// cnt1++;
		ptr = FetchFromCentralCache(alignSize, index);
	}
	return ptr;
}


void ThreadCache::Deallocate(void* obj, size_t size)
{
	assert(obj && size <= MAX_BYTES);
	//将相应空间规划给自由链表:管理自由链表的哈希桶结构
	size_t alignSize = SizeClass::RoundUp(size);
	size_t index = SizeClass::Index(alignSize);//本质不用对齐,可以直接计算在哪个桶中
	_freeLists[index].Push(obj);

	//当链表长度大于一次批量申请的内存时就开始还一段list给central_cache:链表太长,就释放--基于某个桶考虑
	//高于高水位的1.3倍,就释放缓存数到低水位
	if(_freeLists[index].Num() > _freeLists[index].HighLevel() * 1.3)
	{
		// cnt2++;
		ListTooLong(_freeLists[index],index,_freeLists[index].Num() - _freeLists[index].LowLevel());//直接归还到低水位,并且使用滞后机制
	}	
}

//从自由链表中拿出一段
void ThreadCache::ListTooLong(FreeList& list,size_t index,size_t n)
{
	void* start = nullptr;
	void* end = nullptr;
	list.PopRange(start,end,n);
	CentralCache::GetInstance()->ReleaseToCentral(start,index);
}

//线程结束时,归还整个ThreadCache中的资源到CentralCache中,同时释放ThreadCache自身
void ThreadCache::FreeThreadCache()
{
	//复用ListTooLong
	for(int i = 0;i < NFREELISTS;i++)
	{
		if(!_freeLists[i].Empty())
			ListTooLong(_freeLists[i],i,_freeLists[i].Num());
	}
}

ThreadCache::ThreadCache()
{
	//高低水位不同大小的FreeList差异化设计
	//1~1024字节:小对象,低水位512,高水位4倍 桶号[0,72)
	//1025~8*1024:中对象,低水位128,高水位4倍 桶号[72,128)
	//8*1024+1~256*1024:大对象,低水32,高水位4倍,桶号[128,208)

	for(int i = 0;i < 72;i++)
		_freeLists[i].SetWaterLevel(2048,2048 / 4);
	for(int i = 72;i < 128;i++)
		_freeLists[i].SetWaterLevel(512,512 / 4);
	for(int i = 128;i < 208;i++)
		_freeLists[i].SetWaterLevel(128,128 / 4);
}
ThreadCache::~ThreadCache()
{
	FreeThreadCache();//释放资源
}

// void PrintRatio()
// {
// 	std::cout << "申请时,thread_cache访问central_cache的次数是" << cnt1 << std::endl;
// 	std::cout << "释放时,thread_cache访问central_cache的次数是" << cnt2 << std::endl;
// }